package errno

import (
	"fmt"
	"log"
	"reflect"
)

// Errno user define error
type Errno struct {
	Code    int
	Message string
}

// error string method
func (err Errno) Error() string {
	return err.Message
}

// Err represents an error
type Err struct {
	Code    int
	Message string
	Err     error
}

// New create error
func New(errno *Errno, err error) *Err {
	return &Err{Code: errno.Code, Message: errno.Message, Err: err}
}

// Add add message
func (err *Err) Add(message string) error {
	err.Message += " " + message
	return err
}

// Addf add format message
func (err *Err) Addf(format string, args ...interface{}) error {
	err.Message += " " + fmt.Sprintf(format, args...)
	return err
}

// get error msg
func (err *Err) Error() string {
	return fmt.Sprintf("Err - code: %d, message: %s, error: %s", err.Code, err.Message, err.Err)
}

//func IsErrUserNotFound(err error) bool {
//	code, _ := DecodeErr(err)
//	return code == ErrUserNotFound.Code
//}

// DecodeErr decode error
func DecodeErr(err error) (int, string) {
	if err == nil {
		return OK.Code, OK.Message
	}

	switch typed := err.(type) {
	case *Err:
		return typed.Code, typed.Message
	case *Errno:
		// 此处存在rpc压测连接超时出现nil空指针场景，需要校验类型后盼空
		if typed == nil {
			log.Println("decode meet server Errno, ", err, reflect.TypeOf(err), reflect.ValueOf(err))
			return InternalServerError.Code, InternalServerError.Message
		}
		return typed.Code, typed.Message
	default:
		log.Println("decode meet default error, ", err)
	}

	return InternalServerError.Code, err.Error()
}
